"""
版本控制系统

提供自动版本保存、版本差异比较、版本回滚等功能
"""

import json
import hashlib
import difflib
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass, asdict
from pathlib import Path

from ..interfaces.base_component import BaseComponent
from ..models.collaboration_models import Version, VersionDiff, VersionMetadata


@dataclass
class VersionSnapshot:
    """版本快照"""
    version_id: str
    content: str
    metadata: Dict[str, Any]
    timestamp: datetime
    author: str
    message: str
    parent_version: Optional[str] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'version_id': self.version_id,
            'content': self.content,
            'metadata': self.metadata,
            'timestamp': self.timestamp.isoformat(),
            'author': self.author,
            'message': self.message,
            'parent_version': self.parent_version
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'VersionSnapshot':
        """从字典创建"""
        return cls(
            version_id=data['version_id'],
            content=data['content'],
            metadata=data['metadata'],
            timestamp=datetime.fromisoformat(data['timestamp']),
            author=data['author'],
            message=data['message'],
            parent_version=data.get('parent_version')
        )


class VersionControl(BaseComponent):
    """版本控制系统"""
    
    def get_required_configs(self) -> List[str]:
        return ['storage_path', 'auto_save_interval']
    
    def _setup_component(self):
        """设置组件特定的初始化逻辑"""
        self.logger.info("版本控制系统初始化")
        
        # 版本存储
        self.storage_path = Path(self.config.get('storage_path', 'versions'))
        self.storage_path.mkdir(exist_ok=True)
        
        # 版本历史
        self.version_history: Dict[str, List[VersionSnapshot]] = {}
        self.current_versions: Dict[str, str] = {}  # document_id -> version_id
        
        # 自动保存配置
        self.auto_save_interval = self.config.get('auto_save_interval', 300)  # 5分钟
        self.auto_save_enabled = self.config.get('auto_save_enabled', True)
        
        # 版本比较缓存
        self.diff_cache: Dict[str, VersionDiff] = {}
        
        # 加载现有版本历史
        self._load_version_history()
        
        self.logger.info("版本控制系统初始化完成")
    
    def create_version(self, 
                      document_id: str,
                      content: str,
                      author: str,
                      message: str = "",
                      metadata: Optional[Dict[str, Any]] = None) -> str:
        """创建新版本"""
        try:
            # 生成版本ID
            version_id = self._generate_version_id(document_id, content)
            
            # 获取父版本
            parent_version = self.current_versions.get(document_id)
            
            # 创建版本快照
            snapshot = VersionSnapshot(
                version_id=version_id,
                content=content,
                metadata=metadata or {},
                timestamp=datetime.now(),
                author=author,
                message=message,
                parent_version=parent_version
            )
            
            # 保存版本
            if document_id not in self.version_history:
                self.version_history[document_id] = []
            
            self.version_history[document_id].append(snapshot)
            self.current_versions[document_id] = version_id
            
            # 持久化存储
            self._save_version(document_id, snapshot)
            
            self.logger.info(f"创建版本成功: {document_id}@{version_id}")
            return version_id
            
        except Exception as e:
            self.logger.error(f"创建版本失败: {str(e)}")
            raise
    
    def get_version(self, document_id: str, version_id: str) -> Optional[VersionSnapshot]:
        """获取指定版本"""
        try:
            if document_id not in self.version_history:
                return None
            
            for snapshot in self.version_history[document_id]:
                if snapshot.version_id == version_id:
                    return snapshot
            
            return None
            
        except Exception as e:
            self.logger.error(f"获取版本失败: {str(e)}")
            return None
    
    def get_version_history(self, document_id: str) -> List[VersionSnapshot]:
        """获取版本历史"""
        try:
            return self.version_history.get(document_id, [])
            
        except Exception as e:
            self.logger.error(f"获取版本历史失败: {str(e)}")
            return []
    
    def compare_versions(self, 
                        document_id: str,
                        version1_id: str,
                        version2_id: str) -> Optional[VersionDiff]:
        """比较两个版本"""
        try:
            # 检查缓存
            cache_key = f"{document_id}:{version1_id}:{version2_id}"
            if cache_key in self.diff_cache:
                return self.diff_cache[cache_key]
            
            # 获取版本内容
            version1 = self.get_version(document_id, version1_id)
            version2 = self.get_version(document_id, version2_id)
            
            if not version1 or not version2:
                return None
            
            # 计算差异
            diff_result = self._calculate_diff(version1.content, version2.content)
            
            # 创建差异对象
            version_diff = VersionDiff(
                document_id=document_id,
                version1_id=version1_id,
                version2_id=version2_id,
                additions=diff_result['additions'],
                deletions=diff_result['deletions'],
                modifications=diff_result['modifications'],
                similarity_score=diff_result['similarity_score'],
                diff_summary=diff_result['summary']
            )
            
            # 缓存结果
            self.diff_cache[cache_key] = version_diff
            
            return version_diff
            
        except Exception as e:
            self.logger.error(f"版本比较失败: {str(e)}")
            return None
    
    def rollback_to_version(self, 
                           document_id: str,
                           version_id: str,
                           author: str,
                           message: str = "") -> bool:
        """回滚到指定版本"""
        try:
            # 获取目标版本
            target_version = self.get_version(document_id, version_id)
            if not target_version:
                self.logger.error(f"目标版本不存在: {version_id}")
                return False
            
            # 创建回滚版本
            rollback_message = f"回滚到版本 {version_id}: {message}"
            new_version_id = self.create_version(
                document_id=document_id,
                content=target_version.content,
                author=author,
                message=rollback_message,
                metadata={
                    'rollback_target': version_id,
                    'rollback_timestamp': datetime.now().isoformat()
                }
            )
            
            self.logger.info(f"回滚成功: {document_id} -> {version_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"版本回滚失败: {str(e)}")
            return False
    
    def get_current_version(self, document_id: str) -> Optional[str]:
        """获取当前版本ID"""
        return self.current_versions.get(document_id)
    
    def auto_save_version(self, 
                         document_id: str,
                         content: str,
                         author: str) -> Optional[str]:
        """自动保存版本"""
        try:
            if not self.auto_save_enabled:
                return None
            
            # 检查是否需要自动保存
            if not self._should_auto_save(document_id, content):
                return None
            
            # 创建自动保存版本
            version_id = self.create_version(
                document_id=document_id,
                content=content,
                author=author,
                message="自动保存",
                metadata={'auto_save': True}
            )
            
            return version_id
            
        except Exception as e:
            self.logger.error(f"自动保存失败: {str(e)}")
            return None
    
    def _generate_version_id(self, document_id: str, content: str) -> str:
        """生成版本ID"""
        timestamp = datetime.now().isoformat()
        content_hash = hashlib.md5(content.encode()).hexdigest()[:8]
        return f"{document_id}_{timestamp}_{content_hash}"
    
    def _calculate_diff(self, content1: str, content2: str) -> Dict[str, Any]:
        """计算内容差异"""
        lines1 = content1.splitlines()
        lines2 = content2.splitlines()
        
        # 使用difflib计算差异
        differ = difflib.unified_diff(lines1, lines2, lineterm='')
        diff_lines = list(differ)
        
        # 统计变化
        additions = []
        deletions = []
        modifications = []
        
        for line in diff_lines:
            if line.startswith('+') and not line.startswith('+++'):
                additions.append(line[1:])
            elif line.startswith('-') and not line.startswith('---'):
                deletions.append(line[1:])
        
        # 计算相似度
        similarity = difflib.SequenceMatcher(None, content1, content2).ratio()
        
        # 生成摘要
        summary = f"添加 {len(additions)} 行，删除 {len(deletions)} 行"
        
        return {
            'additions': additions,
            'deletions': deletions,
            'modifications': modifications,
            'similarity_score': similarity,
            'summary': summary
        }
    
    def _should_auto_save(self, document_id: str, content: str) -> bool:
        """判断是否应该自动保存"""
        # 获取最新版本
        current_version_id = self.current_versions.get(document_id)
        if not current_version_id:
            return True  # 首次保存
        
        current_version = self.get_version(document_id, current_version_id)
        if not current_version:
            return True
        
        # 检查内容是否有变化
        if current_version.content == content:
            return False
        
        # 检查时间间隔
        time_diff = (datetime.now() - current_version.timestamp).total_seconds()
        return time_diff >= self.auto_save_interval
    
    def _save_version(self, document_id: str, snapshot: VersionSnapshot):
        """保存版本到磁盘"""
        try:
            doc_dir = self.storage_path / document_id
            doc_dir.mkdir(exist_ok=True)
            
            version_file = doc_dir / f"{snapshot.version_id}.json"
            with open(version_file, 'w', encoding='utf-8') as f:
                json.dump(snapshot.to_dict(), f, ensure_ascii=False, indent=2)
                
        except Exception as e:
            self.logger.error(f"保存版本到磁盘失败: {str(e)}")
    
    def _load_version_history(self):
        """从磁盘加载版本历史"""
        try:
            if not self.storage_path.exists():
                return
            
            for doc_dir in self.storage_path.iterdir():
                if not doc_dir.is_dir():
                    continue
                
                document_id = doc_dir.name
                versions = []
                
                for version_file in doc_dir.glob("*.json"):
                    try:
                        with open(version_file, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            snapshot = VersionSnapshot.from_dict(data)
                            versions.append(snapshot)
                    except Exception as e:
                        self.logger.warning(f"加载版本文件失败: {version_file}, {str(e)}")
                
                if versions:
                    # 按时间排序
                    versions.sort(key=lambda v: v.timestamp)
                    self.version_history[document_id] = versions
                    
                    # 设置当前版本
                    self.current_versions[document_id] = versions[-1].version_id
                    
        except Exception as e:
            self.logger.error(f"加载版本历史失败: {str(e)}")
    
    def get_version_statistics(self, document_id: str) -> Dict[str, Any]:
        """获取版本统计信息"""
        try:
            versions = self.get_version_history(document_id)
            if not versions:
                return {}
            
            # 统计信息
            total_versions = len(versions)
            authors = set(v.author for v in versions)
            auto_saves = sum(1 for v in versions if v.metadata.get('auto_save', False))
            
            # 时间范围
            first_version = min(versions, key=lambda v: v.timestamp)
            last_version = max(versions, key=lambda v: v.timestamp)
            
            return {
                'total_versions': total_versions,
                'unique_authors': len(authors),
                'auto_save_count': auto_saves,
                'manual_save_count': total_versions - auto_saves,
                'first_version_time': first_version.timestamp.isoformat(),
                'last_version_time': last_version.timestamp.isoformat(),
                'authors': list(authors)
            }
            
        except Exception as e:
            self.logger.error(f"获取版本统计失败: {str(e)}")
            return {}